﻿using JESAI.ClamAV.NetScannerCore.Enums;
using JESAI.ClamAV.NetScannerCore.Exceptions;
using JESAI.ClamAV.NetScannerCore.Models;
using JESAI.ClamAV.NetScannerCore.ScanResults;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;

namespace JESAI.ClamAV.NetScannerCore
{
    internal static class RawScanResultMapper
    {
        public static ScannerResult ToScanResult(this ClamAVScannerResult rawScanResult)
        {
            if (rawScanResult == null)
            {
                throw new ClamAVScannerResultEmptyOrNullException();
            }

            var rawResult = rawScanResult.Value;

            List<InfectedFile> infectedFiles;
            ScanResponseStatus status;
            Mapper(rawResult, out infectedFiles, out status);

            return new ScannerResult(status, new ReadOnlyCollection<InfectedFile>(infectedFiles), rawResult);
        }

        public static Task<ScannerResult> ToScanResult(this Task<ClamAVScannerResult> rawScanResult)
        {
            if (rawScanResult == null)
            {
                throw new ClamAVScannerResultEmptyOrNullException();
            }

            var rawResult = rawScanResult.Result.Value;

            List<InfectedFile> infectedFiles;
            ScanResponseStatus status;
            Mapper(rawResult, out infectedFiles, out status);

            return new Task<ScannerResult>(() => new ScannerResult(status, new ReadOnlyCollection<InfectedFile>(infectedFiles), rawResult));
        }

        private static void Mapper(string rawResult, out List<InfectedFile> infectedFiles, out ScanResponseStatus status)
        {
            infectedFiles = new List<InfectedFile>();
            status = ScanResponseStatus.Unknown;
            if (rawResult.EndsWith("OK", StringComparison.InvariantCultureIgnoreCase))
            {
                status = ScanResponseStatus.Clean;
            }
            else if (rawResult.EndsWith("ERROR", StringComparison.InvariantCultureIgnoreCase))
            {
                status = ScanResponseStatus.Error;
            }
            else if (rawResult.EndsWith("FOUND", StringComparison.InvariantCultureIgnoreCase))
            {
                status = ScanResponseStatus.VirusDetected;

                var files = rawResult.Split(new[] { "FOUND" }, StringSplitOptions.RemoveEmptyEntries);

                foreach (var file in files)
                {
                    var split = file.Trim().Split(' ');

                    var fileName = $"{split[0]?.Replace(":", "")}";
                    var virusName = split[1];

                    infectedFiles.Add(new InfectedFile(fileName, virusName));
                }
            }
        }
    }
}